<template>
  <div class="chat-edit-area" @click="showEmotionPanel = false">
    <div
      :class="[
        'chat-file-progress',
        {
          'chat-file-sending': uploadStatus === 1,
          'chat-file-send-success': uploadStatus === 2,
          'chat-file-error': uploadStatus === -1
        }
      ]"
      :style="{ width: `${percent}%` }"></div>
    <!--工具栏-->
    <div class="flex-row chat-edit-toolbar">
      <!--富文本编辑器内置菜单-->
      <div ref="toolbar" style="padding-right: 0"></div>
      <!--用户自定义菜单-->
      <div class="flex-row flex-item">
        <!--左侧菜单-->
        <div class="flex-row flex-item">
          <div class="chat-menu" title="表情" @click.stop="showEmotion">
            <i class="w-e-icon-happy toolbar-icon" style="font-size: 1em"></i>
          </div>
          <div class="chat-menu" title="发送图片">
            <ElUpload
              ref="uploadImage"
              class="upload-demo"
              :accept="['.png', '.jpg', '.jpeg', '.gif', '.bmp'].join(',')"
              :show-file-list="false"
              :http-request="ctx => uploadFile(ctx, 'image')"
              :action="action"
              :before-upload="beforeUpload"
              :disabled="readonly"
              :data="bizInfo"
              auto-upload>
              <template #trigger>
                <i class="el-icon-picture toolbar-icon"></i>
              </template>
            </ElUpload>
          </div>
          <div class="chat-menu" title="发送文件">
            <ElUpload
              ref="uploadFile"
              class="upload-demo"
              :show-file-list="false"
              :http-request="ctx => uploadFile(ctx, 'file')"
              :action="action"
              :before-upload="beforeUpload"
              :disabled="readonly"
              :data="bizInfo"
              auto-upload>
              <template #trigger>
                <i class="el-icon-upload toolbar-icon"></i>
              </template>
            </ElUpload>
          </div>
        </div>
        <!--右侧菜单-->
        <div>
          <div class="chat-menu" title="聊天记录">
            <i class="el-icon-time toolbar-icon" @click="showHistory = true"></i>
          </div>
        </div>
      </div>
    </div>
    <!--编辑区-->
    <div class="chat-editor-wrapper">
      <div class="absolute-box">
        <CustomScrollbar v-show="!readonly" class="scroll-wrapper">
          <div ref="editor" class="chat-editor" placeholder="按 Ctrl + Enter 发送" @keyup="sendMsg"></div>
        </CustomScrollbar>
        <EmptyView v-show="readonly" :empty-tips="disabledTips" font-size="14px" />
      </div>
    </div>
    <!--底部-->
    <div class="footer">
      <ElButton v-if="closeable" size="mini" title="关闭(Esc)" @click="close">关闭</ElButton>
      <ElButton
        :disabled="sendButtonDisabled || sending"
        :title="contentEmpty() ? '' : 'Ctrl+Enter'"
        :loading="sending"
        size="mini"
        type="primary"
        @click="sendToServer()">
        发 送
      </ElButton>
    </div>
    <!--消息记录对话框-->
    <ChatHistoryDialog :key="session.id" :session="session" :visible.sync="showHistory" />
    <!--表情面板-->
    <Emotion
      v-show="showEmotionPanel"
      :style="{ left }"
      style="position: absolute; top: -262px; z-index: 2"
      @mouseleave="showEmotionPanel = false"
      @item-click="insertEmotion" />
  </div>
</template>

<script>
  import { sendMessage } from './api/message'
  import { uploadFile } from '@/api/file'
  import ChatHistoryDialog from './ChatHistoryDialog'
  import { RichTextEditor } from '@/components/wang-eidtor'
  import { delay, filterHtml } from '@web-utils/core'
  import { debounce } from 'lodash-es'
  import Emotion from '@/views/playground/widgets/Emotion'
  import { services } from '@/config'

  const delayTime = 3000

  export default {
    name: 'ChatRichTextEditArea',
    components: { Emotion, ChatHistoryDialog },
    props: {
      session: {
        type: Object,
        default: () => {}
      },
      closeable: {
        type: Boolean,
        default: false
      },
      disabled: Boolean,
      disabledTips: String
    },
    data() {
      return {
        showEmotionPanel: false,
        showHistory: false,
        sending: false,
        percent: 0,
        uploadStatus: 0,
        left: '0px',
        text: '',
        sendButtonDisabled: true
      }
    },
    computed: {
      action() {
        return `${services.commonService}file/upload`
      },
      readonly() {
        return this.disabled || !this.session || !this.session.id
      },
      bizInfo() {
        return { bizId: this.session.thread?.id, bizName: 'IM' }
      }
    },
    watch: {
      readonly: {
        immediate: true,
        async handler() {
          await this.$nextTick()
          if (this.readonly) {
            this.editor && this.editor.$textElem.attr('contenteditable', false)
          } else {
            this.editor && this.editor.$textElem.attr('contenteditable', true)
          }
        }
      }
    },
    created() {
      this.debounceClearEmptyHtml = debounce(this.clearEmptyHtml, 100)
    },
    mounted() {
      this.editor = new RichTextEditor(this.$refs.toolbar, this.$refs.editor)
      this.editor.customConfig.zIndex = 1
      // 更多菜单配置 https://www.kancloud.cn/wangfupeng/wangeditor3/335777
      this.editor.customConfig.menus = []
      // this.editor.customConfig.menus = ['fontName']
      // this.editor.customConfig.fontNames = ['宋体', '微软雅黑', 'Arial']
      this.editor.customConfig.onchange = html => {
        this.text = html
        this.clearEmptyHtml()
      }
      this.editor.create()
      this.editorDom = this.$refs.editor.querySelector('.w-e-text')
      this.clearEmptyHtml()
      this.editorDom.addEventListener('focus', this.debounceClearEmptyHtml)
      this.editorDom.addEventListener('keyup', this.debounceClearEmptyHtml)
      this.editorDom.addEventListener('input', this.debounceClearEmptyHtml)
      // this.$refs.toolbar.querySelector('.w-e-menu').setAttribute('title', '字体')
    },
    beforeDestroy() {
      this.editorDom.removeEventListener('focus', this.debounceClearEmptyHtml)
      this.editorDom.removeEventListener('keyup', this.debounceClearEmptyHtml)
      this.editorDom.removeEventListener('input', this.debounceClearEmptyHtml)
    },
    methods: {
      async uploadFile(obj, type) {
        try {
          const res = await uploadFile(obj.action, obj.file, {
            headers: obj.headers,
            onprogress: this.onUploadProgress,
            data: obj.data
          })
          if (type === 'file') {
            await this.onFileUploadSuccess(res.data)
          }
          if (type === 'image') {
            await this.onImageUploadSuccess(res.data)
          }
        } catch (e) {
          await this.onUploadError()
        }
      },
      contentEmpty() {
        if (this.editorDom) {
          const html = this.editorDom.innerHTML
          return !filterHtml(html) && html.indexOf('<img') === -1
        } else {
          return true
        }
      },
      clearEmptyHtml(event) {
        if (event && event.code !== 'Backspace') {
          return
        }
        if (this.contentEmpty()) {
          this.sendButtonDisabled = true
          this.editorDom.innerHTML = ''
          this.$refs.editor && this.$refs.editor.classList.add('chat-editor')
        } else {
          this.sendButtonDisabled = false
          this.$refs.editor && this.$refs.editor.classList.remove('chat-editor')
        }
      },
      close() {
        this.$emit('close')
      },
      insertEmotion(position) {
        this.editor.cmd.do(
          'insertHTML',
          `<img src="/static/img/emotion/${position}.gif" alt="[表情]" data-emotion="${position}">`
        )
      },
      showEmotion(event) {
        if (this.readonly) {
          return
        }
        if (!this.showEmotionPanel) {
          const target = event.target
          this.left = `${target.clientLeft - 3}px`
          this.showEmotionPanel = true
        } else {
          this.showEmotionPanel = false
        }
      },
      sendMsg(e) {
        if (this.text.trim() && e.ctrlKey && e.keyCode === 13 && this.text.length) {
          this.sendToServer()
        }
      },
      async sendToServer(type = 'text', mediaId) {
        try {
          this.sending = true
          const text = this.text
          const temp = this.text.replace(/&nbsp;/g, '').trim()
          if (!temp) {
            this.editorDom.innerHTML = ''
            this.$refs.editor && this.$refs.editor.classList.add('chat-editor')
            this.sending = false
            return
          }

          const res = await sendMessage({ threadId: this.session.thread.id, mediaId, content: text, type })

          this.text = ''
          this.editorDom.innerHTML = ''
          this.$emit('send-success', res.data.data)
        } catch (e) {
          this.$notify.error({
            title: '温馨提示',
            message: '发送失败！',
            position: 'bottom-right',
            duration: 2000
          })
        }
        this.sending = false
      },
      beforeUpload() {
        this.uploadStatus = 1
        return true
      },
      onUploadProgress(event) {
        this.uploadStatus = 1
        this.percent = event.percent
      },
      async onImageUploadSuccess(response) {
        this.uploadStatus = 2
        const { data } = response
        this.text = data.filename
        await this.sendToServer('image', data.id)
        this.$refs.uploadImage.clearFiles()
        await delay(delayTime)
        this.uploadStatus = 0
      },
      async onFileUploadSuccess(response) {
        this.uploadStatus = 2
        const { data } = response
        this.text = data.filename
        await this.sendToServer('file', data.id)
        this.$refs.uploadFile.clearFiles()
        await delay(delayTime)
        this.uploadStatus = 0
      },
      async onUploadError() {
        this.uploadStatus = -1
        this.$message.error('文件发送失败，请重试或联系管理员！')
        await delay(delayTime)
        this.$refs.uploadImage.clearFiles()
        this.$refs.uploadFile.clearFiles()
        this.uploadStatus = 0
      }
    }
  }
</script>

<style lang="scss">
  .chat-edit-area {
    @include flex-not-shrink;
    position: relative;
    z-index: 0;
    display: flex;
    flex-direction: column;
    height: 180px;
    background: #fff;
    border-bottom: solid 1px #e0e0e0;
    border-bottom: none;
    border-radius: 0 0 4px;

    // 编辑器内置菜单
    .w-e-toolbar .w-e-menu {
      padding: 5px 6px;
    }

    .w-e-toolbar .w-e-menu .w-e-icon-font {
      font-family: element-icons !important;

      &::before {
        font-size: 1.1em;
        content: '\e7a9';
      }
    }

    .w-e-text-container {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
      height: 100%;
      overflow: visible;
    }

    .w-e-text {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
      height: 100%;
      padding-top: 10px;
      overflow: visible;
      word-wrap: break-word;
    }

    .w-e-text {
      p,
      h1,
      h2,
      h3,
      h4,
      h5,
      table,
      pre {
        margin: 0;
      }

      p {
        height: 24px;
        line-height: 24px;
      }

      img {
        vertical-align: bottom;
      }
    }

    .chat-file-progress {
      position: absolute;
      top: 0;
      width: 0;
      height: 2px;
      background-color: #f7f7f7;
    }

    .chat-file-sending {
      background-color: var(--color-primary);
    }

    .chat-file-send-success {
      background-color: #80d954;
    }

    .chat-file-error {
      background-color: #f00;
    }

    .footer {
      flex-basis: 40px;
      flex-shrink: 0;
      height: 40px;
      min-height: 40px;
      padding: 6px;
      text-align: right;
    }

    .textarea {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      padding: 10px;
      font-family: 'Micrsofot Yahei', sans-serif;
    }

    .chat-editor-wrapper {
      position: relative;
      flex: 1 1 auto;
      height: 100%;
      overflow: auto;

      .os-content {
        min-height: 100%;
      }

      .chat-editor {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
        cursor: text;

        &::after {
          position: absolute;
          top: 10px;
          left: 11px;
          color: #a9a9a9;
          content: attr(placeholder);
          pointer-events: none;
        }
      }
    }

    .chat-edit-toolbar {
      align-items: center;
      background-color: #eee;

      .chat-menu {
        position: relative;
        padding: 5px 6px;
        text-align: center;
        cursor: pointer;
      }

      .toolbar-icon {
        color: #999;
        font-size: 1.2em;
        cursor: pointer;

        &:hover {
          color: #333;
        }
      }
    }
  }
</style>
